package libamuse

import (
	"notabug.org/apiote/amuse/accounts"
	"notabug.org/apiote/amuse/datastructure"
	"notabug.org/apiote/amuse/db"
	"notabug.org/apiote/amuse/front"
	"notabug.org/apiote/amuse/tmdb"
	"notabug.org/apiote/amuse/wikidata"

	"database/sql"
	"errors"
	"golang.org/x/text/language"

	"notabug.org/apiote/gott"
)

type Data interface {
	getLanguage() string
	getMimeType() string
	getAuth() accounts.Authentication
	getReqUsername() string
}

func verifyToken(args ...interface{}) (interface{}, error) {
	data := args[0].(Data)
	result := args[1].(*Result)
	user, err := VerifyAuthToken(data.getAuth())
	if _, ok := err.(accounts.AuthError); ok && !data.getAuth().Necessary {
		err = nil
	}
	result.user = user
	return gott.Tuple(args), err
}

func verifyUser(args ...interface{}) (interface{}, error) {
	data := args[0].(Data)
	result := args[1].(*Result)
	if result.user.Username != data.getReqUsername() {
		return gott.Tuple(args), accounts.AuthError{Err: errors.New("403")}
	}
	return gott.Tuple(args), nil
}

func createDbConnection(args ...interface{}) (interface{}, error) {
	requestData := args[0].(*RequestData)
	db, err := sql.Open("sqlite3", "./amuse.db")
	if err != nil {
		return gott.Tuple(args), err
	}
	requestData.connection = db
	return gott.Tuple(args), nil
}

func parseLanguage(args ...interface{}) (interface{}, error) {
	data := args[0].(Data)
	result := args[1].(*Result)
	tags, _, err := language.ParseAcceptLanguage(data.getLanguage())
	if tags == nil {
		tags = []language.Tag{}
	}
	if len(tags) == 0 {
		tags = append(tags, language.Make("en-GB"))
	}
	result.languages = tags
	return gott.Tuple(args), err
}

func createRenderer(args ...interface{}) (interface{}, error) {
	data := args[0].(Data)
	result := args[1].(*Result)
	renderer, err := front.NewRenderer(data.getMimeType(), result.user)
	result.renderer = renderer
	return gott.Tuple(args), err
}

func getDescription(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)
	work := result.result.(datastructure.Work)
	var (
		description string
		err         error
	)
	if work.GetArticle() != "" {
		languages := result.languages
		description, err = wikidata.GetWorkDescription(work.GetArticle(), languages[0].String(), data.connection)
	}
	work.SetDescription(description)
	return gott.Tuple(args), err
}

func getBasedOn(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)
	show := result.result.(tmdb.Show)
	languages := result.languages
	book, err := wikidata.GetBookByTmdb(data.id, languages[0].String())
	show.AddBasedOn(book)
	return gott.Tuple(args), err
}

func getGenres(args ...interface{}) (interface{}, error) {
	result := args[1].(*Result)
	list := result.result.(datastructure.List)
	genres, err := tmdb.GetGenres(result.languages[0].String(), list.GetType())
	list.SetGenres(genres)
	result.result = list

	return gott.Tuple(args), err
}

func isOnWantList(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)
	item := result.result.(datastructure.Item)

	if result.user.IsEmpty() {
		return gott.Tuple(args), nil
	}

	itemType := item.GetItemType()

	isOnList, err := db.IsOnWantList(result.user.Username, data.id, itemType)
	item.SetOnWantList(isOnList)
	return gott.Tuple(args), err
}

func updateCache(args ...interface{}) (interface{}, error) {
	data := args[0].(*RequestData)
	result := args[1].(*Result)

	item := result.result.(datastructure.Item)

	itemInfo := item.GetItemInfo()

	err := db.UpdateCacheItem(item.GetItemType(), data.id, itemInfo)
	return gott.Tuple(args), err
}

type RequestData struct {
	id         string
	etag       string
	connection *sql.DB
	language   string
	mimetype   string
	code       int
	auth       accounts.Authentication
	username   string
}

type Result struct {
	languages []language.Tag
	renderer  front.Renderer
	user      accounts.User
	result    interface{}
	result2   interface{} // todo this is ugly -> to []interface{} with .result
	page      string
}

func (d RequestData) getLanguage() string {
	return d.language
}

func (d RequestData) getMimeType() string {
	return d.mimetype
}

func (d RequestData) getAuth() accounts.Authentication {
	return d.auth
}

func (d RequestData) getReqUsername() string {
	return d.username
}
